package com.iqiyi.pps.epg.core.service.carousel;

import com.alibaba.fastjson.JSONObject;
import com.iqiyi.kiwi.utils.Configuration;
import com.iqiyi.pps.epg.core.async.AsyncService;
import com.iqiyi.pps.epg.core.async.HeartBeatCenter;
import com.iqiyi.pps.epg.core.async.IAsyncTask;
import com.iqiyi.pps.epg.core.async.IHeartBeat;
import com.iqiyi.pps.epg.core.model.carousel.AutoCarouselEpisodeLibrary;
import com.iqiyi.pps.epg.core.model.carousel.AutoCarouselEpisodeRule;
import com.iqiyi.pps.epg.core.model.carousel.ProgramQipuData;
import com.iqiyi.pps.epg.core.model.channel.ChannelBase;
import com.iqiyi.pps.epg.core.model.channel.SearchSettingConfig;
import com.iqiyi.pps.epg.core.model.program.ProgramData;
import com.iqiyi.pps.epg.core.model.task.SimpleTask;
import com.iqiyi.pps.epg.core.model.task.SimpleTaskStatus;
import com.iqiyi.pps.epg.core.model.task.SimpleTaskType;
import com.iqiyi.pps.epg.core.service.channel.ChannelService;
import com.iqiyi.pps.epg.core.service.notifymail.NotifyMailService;
import com.iqiyi.pps.epg.core.service.program.ProgramService;
import com.iqiyi.pps.epg.core.service.task.SimpleTaskService;
import com.iqiyi.pps.epg.core.utils.*;
import com.iqiyi.pps.epg.core.utils.mail.MailConstant;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;

/**
 * Created by karkarrotxu on 2016/1/18.
 */
@Service
@Transactional
public class CarouselAsyncServiceImpl extends AsyncService implements InitializingBean, IHeartBeat, ICarouselAsyncService {
    private static final Logger logger = LoggerFactory.getLogger(CarouselAsyncServiceImpl.class);
    private final static long HEARTBEAT_DELAY = 1000 * 60; //
    private final static long HEARTBEAT_DELAY2 = 1000 * 60; //
    private long heartBeatTime = 0;
    private long heartBeatTime2 = 0;
    private static final int SIZE_LENGTH = 2048;
    public static String ASSIGN_WORK_IP = "10.153.108.204";
    @Autowired
    private SimpleTaskService simpleTaskService;

    @Autowired
    private ProgramService programService;

    @Autowired
    private CarouselService carouselService;

    @Autowired
    private ChannelService channelService;

    @Autowired
    private NotifyMailService notifyMailService;

    protected boolean queryEnable() {
        return getEnable("carousel");
    }
    public void afterPropertiesSet() throws Exception {
        logger.info("CarouselAsyncServiceImpl afterPropertiesSet");
        HeartBeatCenter.add(this);
    }

    @Override
    public void tick(long now) {
        if (now - heartBeatTime >= HEARTBEAT_DELAY) {
            heartBeatTime = now;
            logger.info("CAROUSEL_AUTOMATION_START tick");
            triggerStartOnce();
            logger.info("CAROUSEL_AUTOMATION_PROGRAM_START tick");
            triggerProgramStartOnce();
        }
        if (now - heartBeatTime2 >= HEARTBEAT_DELAY2) {
            heartBeatTime2 = now;
            logger.info("CAROUSEL_AUTOMATION_APPEND tick");
            triggerAppendOnce();
            logger.info("CAROUSEL_AUTOMATION_PROGRAM_APPEND tick");
            triggerProgramAppendOnce();
        }
    }

    public void triggerStartOnce() {
        this.accept(new IAsyncTask() {
            @Override
            public void doTask() {
                executeSimpleTaskList(SimpleTaskType.CAROUSEL_AUTOMATION_START.getTypeIndex(), SimpleTaskStatus.WAIT.getStatusIndex(), true);
            }
        });
    }

    @Override
    public void triggerAppendOnce() {
        this.accept(new IAsyncTask() {
            @Override
            public void doTask() {
                executeSimpleTaskList(SimpleTaskType.CAROUSEL_AUTOMATION_APPEND.getTypeIndex(), SimpleTaskStatus.WAIT.getStatusIndex(), true);
            }
        });
    }

    public void triggerProgramStartOnce() {
        this.accept(new IAsyncTask() {
            @Override
            public void doTask() {
                executeSimpleTaskList(SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_START.getTypeIndex(), SimpleTaskStatus.WAIT.getStatusIndex(), true);
            }
        });
    }

    @Override
    public void triggerProgramAppendOnce() {
        this.accept(new IAsyncTask() {
            @Override
            public void doTask() {
                executeSimpleTaskList(SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_APPEND.getTypeIndex(), SimpleTaskStatus.WAIT.getStatusIndex(), true);
            }
        });
    }

    @Override
    public int changeAutomationTask(long channelId, int execStatus) {
        channelService.notifyHasPrograms(channelId);
        int execStatusNew = 0;
        int execStatusOld = 0;
        int flag = 0;
        switch (execStatus) {
            case AutoCarouselEpisodeRule.STATUS_RUN:
                execStatusNew = 1;
                break;
            case AutoCarouselEpisodeRule.STATUS_IDLE:
                execStatusOld = 1;
                break;
            // AutoCarouselEpisodeRule PROGRAM_RUN
            case AutoCarouselEpisodeRule.STATUS_PROGRAM_RUN:
                if (!carouselService.hasEpisodeLibraryByChannelId(channelId)) {
                    return -1;
                }
                if (carouselService.isLibraryRuleRunning(channelId)) {
                    return -2;
                }
                createVirtualRule(channelId);
                break;
            // AutoCarouselEpisodeRule PROGRAM_IDLE
            case AutoCarouselEpisodeRule.STATUS_PROGRAM_IDLE:
                execStatusOld = 1;
                execStatusNew = -1;
                break;
        }
        if (execStatus != AutoCarouselEpisodeRule.STATUS_PROGRAM_RUN) {
            flag = carouselService.changeAutomationStatus(channelId, execStatusNew, execStatusOld);
        } else {
            flag = 1;
        }
        if ((execStatus == AutoCarouselEpisodeRule.STATUS_RUN || execStatus == AutoCarouselEpisodeRule.STATUS_PROGRAM_RUN)
                && flag > 0) {
            interruptRunningTask(channelId, execStatus);
            addAutomationStartTask(channelId,
                    execStatus == AutoCarouselEpisodeRule.STATUS_RUN ?
                            SimpleTaskType.CAROUSEL_AUTOMATION_START.getTypeIndex() :
                            SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_START.getTypeIndex());
        }
        return flag;
    }

    private boolean createVirtualRule(long channelId) {
        try {
            AutoCarouselEpisodeRule virtualRule = new AutoCarouselEpisodeRule();
            virtualRule.setFatherId(channelId);
            virtualRule.setQipuId(0);
            virtualRule.setType(AutoCarouselEpisodeRule.TYPE_PROGRAM);
            virtualRule.setShowName("");
            virtualRule.setTotalNum(0);
            virtualRule.setChannelTag("");
            virtualRule.setBossStatus(1);
            virtualRule.setPublishStatus(2);
            virtualRule.setCreatedTime(new Timestamp(System.currentTimeMillis()));
            virtualRule.setOpUser(Constants.SYSTEM_USER_SIGN);
            virtualRule.setActualNum(0);
            virtualRule.setStatus(AutoCarouselEpisodeRule.STATUS_RUN);
            virtualRule.setPageUrl("");
            virtualRule.setExecuteTime(new Timestamp(System.currentTimeMillis()));
            virtualRule.setExecIndex(System.currentTimeMillis());
            carouselService.saveAutomation(virtualRule);
        } catch (Exception e) {
            logger.info("[CarouselAsyncServiceImpl][createVirtualRule][channelId=" + channelId + "] " + e);
            return false;
        }
        return true;
    }

    private void interruptRunningTask(long channelId, int execStatus) {
        if (execStatus == AutoCarouselEpisodeRule.STATUS_RUN) {
            int effectNum = simpleTaskService.interruptTask(channelId, SimpleTaskType.CAROUSEL_AUTOMATION_START.getTypeIndex());
            logger.info("[effectNum]CAROUSEL_AUTOMATION_START cId {},effectNum={}:" + channelId, effectNum);
            effectNum = simpleTaskService.interruptTask(channelId, SimpleTaskType.CAROUSEL_AUTOMATION_APPEND.getTypeIndex());
            logger.info("[effectNum]CAROUSEL_AUTOMATION_APPEND cId {},effectNum={}:" + channelId, effectNum);
        } else if (execStatus == AutoCarouselEpisodeRule.STATUS_PROGRAM_RUN) {
            int effectNum = simpleTaskService.interruptTask(channelId, SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_START.getTypeIndex());
            logger.info("[effectNum]CAROUSEL_AUTOMATION_PROGRAM_START cId {},effectNum={}:" + channelId, effectNum);
            effectNum = simpleTaskService.interruptTask(channelId, SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_APPEND.getTypeIndex());
            logger.info("[effectNum]CAROUSEL_AUTOMATION_PROGRAM_APPEND cId {},effectNum={}:" + channelId, effectNum);
        }
    }

    private void addAutomationStartTask(long channelId, int taskType) {
        int createDay = Configuration.getInt("automation.createDay");
        SimpleTask simpleTask = new SimpleTask();
        JSONObject jsonObject = new JSONObject();
        simpleTask.setServerIp(RequestUtils.getLoadlIpByOS());
        simpleTask.setWorkIp(isProductionEnv() ? ASSIGN_WORK_IP : simpleTask.getServerIp());
        simpleTask.setEntityId(channelId);
        simpleTask.setTaskStatus(SimpleTaskStatus.WAIT.getStatusIndex());
        jsonObject.put("createStartTime", System.currentTimeMillis() + DateTimeUtil.MINUTE_TIME * 40);
        jsonObject.put("createDay", createDay);
        simpleTask.setTaskType(taskType);
        simpleTask.setCreateTime(new Timestamp(System.currentTimeMillis()));
        simpleTask.setExpireTime(new Timestamp(System.currentTimeMillis() + DateTimeUtil.DAY_TIME));
        simpleTask.setParams(jsonObject.toJSONString());
        simpleTaskService.saveTask(simpleTask);
    }

    // 生成自动化【节目】
    private boolean doCreateAutomationProgram(SimpleTask simpleTask, long newStartTime, long stopCreateTime, JSONObject params) {
        logger.info("[doCreateAutomationProgram start][sid={}][newStartTime={}][stopCreateTime={}][params={}]",
                simpleTask.getId(), newStartTime, stopCreateTime, params.toJSONString());
        if (newStartTime >= stopCreateTime) {
            logger.info("[doCreateAutomationProgram quick end]  sid={} newStartTime={},stopCreateTime={}", simpleTask.getId(), newStartTime, stopCreateTime);
            return true;
        }

        try {
            List<AutoCarouselEpisodeRule> list = carouselService.getCarouselAutomationList(simpleTask.getEntityId());
            if (null == list || list.size() < 1) {
                logger.info("[doCreateAutomationProgram has no rule]  sid={}", simpleTask.getId());
                return false;
            } else if (list.size() > 1) {
                logger.info("[doCreateAutomationProgram has more than 1 rule]  sid={}", simpleTask.getId());
            }

            AutoCarouselEpisodeRule virtualRule = list.get(0);

            boolean overTime = newStartTime >= stopCreateTime;
            long tempCountTime = newStartTime;

            long repeatCount = 0;

            if (virtualRule.getExecuteTime().getTime() > tempCountTime) {
                logger.info("simpleTask:{} virtualRule {} {} >  {} ",
                        simpleTask.getId(), virtualRule.getId(), virtualRule.getExecuteTime().getTime(), tempCountTime);
                doTaskError(simpleTask);
                return false;
            }

            List<AutoCarouselEpisodeLibrary> programList = carouselService.getCarouselAutomationProgramList(simpleTask.getEntityId());

            if (programList.size() < 1) {
                logger.info("simpleTask:{} virtualRule {} no program in library ",
                        simpleTask.getId(), virtualRule.getId());
                doTaskError(simpleTask);
                return false;
            }

            int nodeLength = programList.size();
            AutoProgramNode programNode = makeUpProgramNode(programList);
            AutoProgramNode currentNode = programNode.getCurrentUse(virtualRule.getCurrentExec());

            if (null == currentNode) {
                currentNode = programNode.getFirstNode();
                if (null == currentNode) {
                    logger.info("simpleTask:{} current use is null", simpleTask.getId());
                    doTaskError(simpleTask);
                    return false;
                }
            }

            Map<Long, ProgramQipuData> cacheMap = new HashMap<>();

            ProgramData original = null;
            ChannelBase channelBase = channelService.getChannelBase(virtualRule.getFatherId());
            List<ProgramData> retList = new ArrayList<ProgramData>(128);
            Map<Long, AutoCarouselEpisodeLibrary> retProgramMap = new HashMap<>();
            long currentAddTime = System.currentTimeMillis();

            long totalCount = 0;
            while (!overTime) {
                repeatCount++;
                //无效数据提前中断循环，将执行失败状态写回数据库
                if (0 == totalCount && repeatCount > nodeLength) {
                    doNoDataError(simpleTask);
                    carouselService.saveAutoProgramDataList(makeLibraryListFromMap(retProgramMap), virtualRule.getFatherId());
                    return false;
                }
                boolean batchUpdate = false;
                int batchAddNum = 50;
                ProgramQipuData tempProgram = cacheMap.get(currentNode.getProgram().getQipuId());
                if (null == tempProgram) {
                    tempProgram = ApiQipuUtil.queryByQipuIdAndCheck(
                            currentNode.getProgram().getQipuId(), channelService.getSearchConfig(virtualRule.getFatherId()),
                            channelBase);
                    original = tempProgram.getOriginal();
                    original.setAutomationRuleId(virtualRule.getId());
                    original.setFatherId((int) virtualRule.getFatherId());
                    original.setAddTime(new Timestamp(currentAddTime));
                    original.setLive(ProgramData.TYPE_DEMAND);
                    original.setType(7);//轮播台节目
                    original.setAlbumName(virtualRule.getShowName());
                    cacheMap.put(currentNode.getProgram().getQipuId(), tempProgram);
                }
                if ( tempProgram.isIllegal()) {
                    currentNode.getProgram().setExecResult(AutoCarouselEpisodeLibrary.EXECUTE_RESULT_FAILED);
                    retProgramMap.put(currentNode.getProgram().getId(), currentNode.getProgram());
                    currentNode = currentNode.getNextNode();
                    continue;
                }
                tempProgram = CarouselAssistUtil.getProgramDataInstance(tempProgram);
                CarouselAssistUtil.fillDefaultValue(channelBase, tempProgram);
                original = tempProgram.getOriginal();
                original.setStartPlayTime(new Timestamp(tempCountTime));
                original.setStreamStartTime(new Timestamp(tempCountTime));
                tempCountTime += DateTimeUtil.SECOND * original.getDuration();
                original.setStopPlayTime(new Timestamp(tempCountTime));
                original.setStreamEndTime(new Timestamp(tempCountTime));
                ProgramData.calPlayStatus(original);
                retList.add(original);
                totalCount++;
                currentNode.getProgram().setExecResult(AutoCarouselEpisodeLibrary.EXECUTE_RESULT_FAILED);
                retProgramMap.put(currentNode.getProgram().getId(), currentNode.getProgram());
                if (tempCountTime >= stopCreateTime) {
                    overTime = true;
                    batchUpdate = true;
                } else if (retList.size() == batchAddNum || retProgramMap.size() == batchAddNum) {
                    batchUpdate = true;
                }
                if (batchUpdate) {
                    params.put("hasCreateTime", tempCountTime);

                    if (simpleTask.getTaskStatus() == SimpleTaskStatus.WAIT.getStatusIndex()) {
                        simpleTask.setParams(params.toJSONString());
                    } else {
                        logger.info("simpleTask sid={} taskStatus={}", simpleTask.getId(), simpleTask.getTaskStatus());
                        return false;
                    }
                    virtualRule.setCurrentExec((int) currentNode.getNextNode().getProgram().getId());
                    virtualRule.setExecuteTime(new Timestamp(tempCountTime));
                    carouselService.saveAutomation(virtualRule);
                    programService.saveProgramDataList(retList, virtualRule.getFatherId());
                    simpleTaskService.saveTask(simpleTask);
                    carouselService.saveAutoProgramDataList(makeLibraryListFromMap(retProgramMap), virtualRule.getFatherId());
                    retList.clear();
                    retProgramMap.clear();
                }
                currentNode = currentNode.getNextNode();
            }

        } catch (Exception e) {
            logger.error("[doCreateAutomationProgram]", e);
            return false;
        }
        logger.info("[doCreateAutomationProgram end] sid={}", simpleTask.getId());
        return true;
    }

    private List<AutoCarouselEpisodeLibrary> makeLibraryListFromMap(Map<Long, AutoCarouselEpisodeLibrary> episodeMap) {
        List<AutoCarouselEpisodeLibrary> result = new ArrayList<>();
        for (Map.Entry<Long, AutoCarouselEpisodeLibrary> entry : episodeMap.entrySet()) {
            result.add(entry.getValue());
        }

        return result;
    }

    private boolean doCreateProgramEnhance(SimpleTask simpleTask, long newStartTime, long stopCreateTime, JSONObject params) {
        logger.info("[doCreateProgramEnhance start] sid={}", simpleTask.getId());
        long taskBeginTime = System.currentTimeMillis();
        if (newStartTime >= stopCreateTime) {
            logger.info("[doCreateProgramEnhance quick end ]  sid={} newStartTime={},stopCreateTime={}",
                    simpleTask.getId(), newStartTime, stopCreateTime);
            return true;
        }
        HashSet<AutoCarouselEpisodeRule> ruleSet = new HashSet<AutoCarouselEpisodeRule>();
        try {
            List<AutoCarouselEpisodeRule> list = carouselService.getCarouselAutomationList(simpleTask.getEntityId());
            RuleNode ruleNode = makeUpRuleNode(list);
            RuleNode currentUse = ruleNode.getCurrentUse();
            if (currentUse == null) {
                currentUse = ruleNode.getFirstNode();
                if (currentUse == null) {
                    logger.info("simpleTask:{} current use is null", simpleTask.getId());
                    doTaskError(simpleTask);
                    return false;
                }
            }

            boolean overTime = newStartTime >= stopCreateTime;
            long tempCountTime = newStartTime;
            long repeatCount = 0;
            SearchSettingConfig config = channelService.getSearchConfig(simpleTask.getEntityId());
            ChannelBase channelBase = channelService.getChannelBase(simpleTask.getEntityId());
            boolean checkNext = false;
            boolean batchUpdate = false;
            List<ProgramData> retList = new ArrayList<ProgramData>(256);
            int count = 0;
            int batchAddNum = 150;
            long episodeId = 0l;
            long totalCount = 0;
            int nodeLength = list.size();
            while (!overTime) {
                repeatCount++;
                if (0 == totalCount && repeatCount > nodeLength) {
                    doNoDataError(simpleTask);
                    return false;
                }
                AutoCarouselEpisodeRule rule = currentUse.getRule();
                rule.setCurrentExec(1);
                if (rule.getExecuteTime().getTime() > tempCountTime) {
                    logger.info("simpleTask:{} rule {} {} >  {} ", simpleTask.getId(), rule.getId(), rule.getExecuteTime().getTime(), tempCountTime);
                    doTaskError(simpleTask);
                    return false;
                }

                String cacheKey = rule.getFatherId() + "_" + rule.getQipuId();
                AlbumLegoDataCache albumLegoDataCache = ApiLegoUtil.getValidCache(cacheKey);
                List<Long> children = null;
                AlbumLegoData albumLegoData = null;
                if (albumLegoDataCache == null) {
                    albumLegoData = ApiLegoUtil.queryAlbumId(rule.getQipuId());
                    children = ApiLegoUtil.collectValidProgram00(albumLegoData, config);
                    ApiLegoUtil.addLegoDataCache(cacheKey, albumLegoData, children);
                } else {
                    albumLegoData = albumLegoDataCache.getAlbumLegoData();
                    children = albumLegoDataCache.getChildren();
                }

                if (children == null) {
                    children = new ArrayList<Long>();
                    logger.info("[ruleId={}][qipuId={}] children is null", rule.getId(), rule.getQipuId());
                }
                logger.info("children.size:" + children.size());

                if (rule.getLastCreatedNo() == 0) {
                    if (albumLegoData.getChildrenNum() > rule.getActualNum()) {
                        rule.setActualNum(albumLegoData.getChildrenNum());
                        ruleSet.add(rule);
                        // carouselService.saveAutomation(rule);
                        logger.info("[albumLegoData] updateActualNum = {},ruleId={}", albumLegoData.getChildrenNum(), rule.getId());
                    }
                }
                if (rule.getActualNum() < albumLegoData.getChildrenNum()) {
                    children = children.subList(0, rule.getActualNum());
                }
                int length = children.size();

                if (rule.getLastCreatedNo() >= length) {
                    checkNext = true;
                } else {
                    ProgramQipuData childEntity = null;
                    ProgramData original = null;
                    long currentAddTime = System.currentTimeMillis();

                    for (int i = rule.getLastCreatedNo(); i < length; i++) {
                        episodeId = children.get(i);
                        childEntity = ApiQipuUtil.queryByQipuIdAndCheck(episodeId, config, channelBase);
                        logger.info("childEntity:{},illegal:{},duration:{}", episodeId, childEntity.isIllegal(), childEntity.getDuration());
                        if (!childEntity.isIllegal()) {
                            count++;
                            totalCount++;
                            original = childEntity.getOriginal();
                            original.setAutomationRuleId(rule.getId());
                            original.setFatherId((int) rule.getFatherId());
                            original.setAddTime(new Timestamp(currentAddTime));
                            original.setLive(ProgramData.TYPE_DEMAND);
                            original.setType(7);//轮播台节目
                            original.setStartPlayTime(new Timestamp(tempCountTime));
                            original.setStreamStartTime(new Timestamp(tempCountTime));
                            tempCountTime += DateTimeUtil.SECOND * original.getDuration();
                            original.setStopPlayTime(new Timestamp(tempCountTime));
                            original.setStreamEndTime(new Timestamp(tempCountTime));
                            ProgramData.calPlayStatus(original);
                            original.setAlbumName(rule.getShowName());
                            CarouselAssistUtil.fillDefaultValue(channelBase, childEntity);
                            retList.add(original);
                        } else {
                            currentUse.addIllegalCount();
                        }
                        logger.info("tempCountTime:{};stopCreateTime:{},repeatCount:{}", tempCountTime, stopCreateTime, repeatCount);
                        if (tempCountTime >= stopCreateTime) {
                            overTime = true;
                            batchUpdate = true;
                        } else if (i == length - 1 && count > 0) {
                            checkNext = true;
                        } else if (count == batchAddNum) {
                            batchUpdate = true;
                        }
                        if (currentUse.isSkip()) {
                            checkNext = true;
                            logger.info("rule illegal id:{}", rule.getId());
                            rule.setStatus(AutoCarouselEpisodeRule.STATUS_ILLEGAL);
                            ruleSet.add(rule);
                        }
                        if (batchUpdate) {
                            batchUpdate = false;
                            params.put("hasCreateTime", tempCountTime);
                            //
                            simpleTask = simpleTaskService.findById(simpleTask.getId());
                            if (simpleTask.getTaskStatus() == SimpleTaskStatus.WAIT.getStatusIndex()) {
                                simpleTask.setParams(params.toJSONString());
                            } else {
                                logger.info("simpleTask sid={} taskStatus={}", simpleTask.getId(), simpleTask.getTaskStatus());
                                return false;
                            }
                            rule.setLastCreatedNo(i + 1);
                            rule.setExecuteTime(new Timestamp(tempCountTime));
                            ruleSet.add(rule);
                            //  carouselService.saveAutomation(rule);
                            programService.saveProgramDataList(retList, rule.getFatherId());
                            simpleTaskService.saveTask(simpleTask);
                            count = 0;
                            retList.clear();
                        }
                        if (overTime) {
                            break;
                        }
                    }
                }

                if (checkNext) {
                    checkNext = false;
                    AutoCarouselEpisodeRule endRule = currentUse.doLoopEnd();
                    ruleSet.add(endRule);
                    // carouselService.saveAutomation(endRule);
                    currentUse = currentUse.getNextAvailable();
                    if (currentUse == null) {
                        doTaskError(simpleTask);
                        return false;
                    }
                    AutoCarouselEpisodeRule startRule = currentUse.doLoopStart();
                    ruleSet.add(startRule);
                    // carouselService.saveAutomation(startRule);
                }
            }
            return true;
        } catch (Exception e) {
            logger.error("[doCreateProgramEnhance] sid=" + simpleTask.getId(), e);
            return false;
        } finally {
            logger.info("[doCreateProgramEnhance end] sid={}", simpleTask.getId());
            if (ruleSet.size() > 0) {
                logger.info("finally update [sid={}][ruleSet.size={}] :", simpleTask.getId(), ruleSet.size());
                carouselService.updateAutomationList(new ArrayList<AutoCarouselEpisodeRule>(ruleSet));
            }
            logger.info("[sid={}][taskCostTime={}]", simpleTask.getId(), System.currentTimeMillis() - taskBeginTime);
        }
    }

    public static RuleNode makeUpRuleNode(List<AutoCarouselEpisodeRule> list) {
        RuleNode firstNode = null;
        RuleNode nodeTemp = null;
        RuleNode lastNode = null;
        for (AutoCarouselEpisodeRule temp : list) {
            nodeTemp = new RuleNode(temp);
            if (lastNode != null) {
                lastNode.setNextNode(nodeTemp);
            }
            lastNode = nodeTemp;
            if (firstNode == null) {
                firstNode = nodeTemp;
                firstNode.setFirstSign(true);
            }
        }
        if (lastNode != null) {
            lastNode.setEndSign(true);
        }
        if (firstNode != null) {
            lastNode.setNextNode(firstNode);
        }
        return firstNode;
    }


    public static AutoProgramNode makeUpProgramNode(List<AutoCarouselEpisodeLibrary> list) {
        AutoProgramNode firstNode = null;
        AutoProgramNode nodeTemp = null;
        AutoProgramNode lastNode = null;
        for (AutoCarouselEpisodeLibrary temp : list) {
            nodeTemp = new AutoProgramNode(temp);
            if (lastNode != null) {
                lastNode.setNextNode(nodeTemp);
            }
            lastNode = nodeTemp;
            if (firstNode == null) {
                firstNode = nodeTemp;
                firstNode.setFirstSign(true);
            }
        }
        if (lastNode != null) {
            lastNode.setEndSign(true);
        }
        if (firstNode != null) {
            lastNode.setNextNode(firstNode);
        }
        return firstNode;
    }

//    public void addAutomationQueryExecuteTask(long triggerTime, int dayAfter) {
//        SimpleTask simpleTask = new SimpleTask();
//        JSONObject jsonObject = new JSONObject();
//        simpleTask.setServerIp(RequestUtils.getLoadlIpByOS());
//        simpleTask.setWorkIp(simpleTask.getServerIp());
//        simpleTask.setEntityId(0);
//        simpleTask.setTaskStatus(SimpleTaskStatus.WAIT.getStatusIndex());
//        jsonObject.put("triggerTime", triggerTime);
//        jsonObject.put("checkEndTime", DateTimeUtil.getDayEndTime(triggerTime + DateTimeUtil.DAY_TIME * dayAfter));
//        simpleTask.setTaskType(SimpleTaskType.CAROUSEL_AUTOMATION_QUERY_EXECUTE.getTypeIndex());
//        simpleTask.setCreateTime(new Timestamp(System.currentTimeMillis()));
//        simpleTask.setExpireTime(new Timestamp(System.currentTimeMillis() + DateTimeUtil.DAY_TIME));
//        simpleTask.setParams(jsonObject.toJSONString());
//        simpleTaskService.saveTask(simpleTask);
//        triggerAppendQueryOnce();
//    }


    @Override
    public void addAutomationAppendTask(long channelId, long checkEndTime, int taskType) {
        logger.info("[addAutomationAppendTask] channelId={},checkEndTime={}", channelId, checkEndTime);
        SimpleTask simpleTask = new SimpleTask();
        JSONObject jsonObject = new JSONObject();
        simpleTask.setServerIp(RequestUtils.getLoadlIpByOS());
        simpleTask.setWorkIp(isProductionEnv() ? ASSIGN_WORK_IP : simpleTask.getServerIp());
        simpleTask.setEntityId(channelId);
        simpleTask.setTaskStatus(SimpleTaskStatus.WAIT.getStatusIndex());
        jsonObject.put("triggerTime", System.currentTimeMillis());
        jsonObject.put("checkEndTime", checkEndTime);
        simpleTask.setTaskType(taskType == AutoCarouselEpisodeRule.TYPE_PROGRAM ?
                SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_APPEND.getTypeIndex() :
                SimpleTaskType.CAROUSEL_AUTOMATION_APPEND.getTypeIndex());
        simpleTask.setCreateTime(new Timestamp(System.currentTimeMillis()));
        simpleTask.setExpireTime(new Timestamp(System.currentTimeMillis() + DateTimeUtil.DAY_TIME));
        simpleTask.setParams(jsonObject.toJSONString());
        simpleTaskService.saveTask(simpleTask);
    }


    protected void executeSimpleTaskList(int type, int status, boolean needOverride) {
        logger.info("[executeSimpleTaskList] execute type:{},status={}", type, status);
        try {
            List<SimpleTask> resultList = simpleTaskService.findList(type, status);
            if (resultList == null || resultList.size() == 0) {
                logger.info("[result empty] resultList == null :" + (resultList == null));
                return;
            }
            logger.info("[executeSimpleTaskList] execute size:" + resultList.size());
            long currentTime = System.currentTimeMillis();
            if (needOverride) {
                Collections.reverse(resultList);
            }
            List<SimpleTask> updateList = new ArrayList<SimpleTask>(SIZE_LENGTH);
            Map<Long, SimpleTask> checkMap = new HashMap<Long, SimpleTask>(SIZE_LENGTH);
            List<SimpleTask> waitToDealList = new ArrayList<SimpleTask>(SIZE_LENGTH);
            for (SimpleTask simpleTask : resultList) {
                if (currentTime > simpleTask.getExpireTime().getTime()) {
                    simpleTask.setTaskStatus(SimpleTaskStatus.EXPIRED.getStatusIndex());
                    updateList.add(simpleTask);
                } else {
                    if (needOverride) {
                        if (!checkMap.containsKey(simpleTask.getEntityId())) {
                            checkMap.put(simpleTask.getEntityId(), simpleTask);
                        } else {
                            simpleTask.setTaskStatus(SimpleTaskStatus.OVERRIDE.getStatusIndex());
                            updateList.add(simpleTask);
                        }
                    } else {
                        waitToDealList.add(simpleTask);
                    }
                }
            }
            logger.info("[executeSimpleTaskList] overtime size:" + updateList);
            if (updateList.size() > 0) {
                simpleTaskService.batchUpdateList(updateList);
            }

            if (checkMap.size() > 0) {
                waitToDealList.addAll(checkMap.values());
            }

            if (waitToDealList.size() > 0) {
                updateList.clear();

                for (SimpleTask simpleTask : waitToDealList) {
                    if (executeSimpleTask(simpleTask)) {
                        updateList.add(simpleTask);
                    }
                }
                if (updateList.size() > 0) {
                    simpleTaskService.batchUpdateList(updateList);
                }
            }
        } catch (Exception e) {
            logger.error("[executeSimpleTaskList] error", e);
        }
        logger.info("[executeSimpleTaskList] execute end");
    }

    protected boolean executeSimpleTask(SimpleTask simpleTask) {
        SimpleTaskType type = SimpleTaskType.getTypeByIndex(simpleTask.getTaskType());
        boolean flag = false;
        switch (type) {
            case CAROUSEL_AUTOMATION_START:
                flag = doAutomationStart(simpleTask);
                break;
            case CAROUSEL_AUTOMATION_APPEND:
                flag = doAutomationAppend(simpleTask);
                break;
            case CAROUSEL_AUTOMATION_PROGRAM_START:
                flag = doAutomationStart(simpleTask);
                break;
            case CAROUSEL_AUTOMATION_PROGRAM_APPEND:
                flag = doAutomationAppend(simpleTask);
                break;
        }
        if (flag) {
            simpleTask.setTaskStatus(SimpleTaskStatus.COMPLETE.getStatusIndex());
            simpleTask.setCompleteTime(new Timestamp(System.currentTimeMillis()));
        }
        return flag;
    }

    private boolean doAutomationStart(SimpleTask simpleTask) {
        ChannelBase channelBase = channelService.getChannelBase(simpleTask.getEntityId());
        if (channelBase == null || channelBase.getIsEnable() == -1) {
            logger.info("[doAutomationStart] channel delete {}", simpleTask.getEntityId());
            doTaskError(simpleTask);
            return false;
        }
        logger.info("[doAutomationStart] sid={}", simpleTask.getId());
        JSONObject params = JSONObject.parseObject(simpleTask.getParams());
        long startTime = params.getLongValue("createStartTime");
        int createDay = params.getIntValue("createDay");
        long hasCreateTime = params.getLongValue("hasCreateTime");
        long stopCreateTime = DateTimeUtil.getDayEndTime(startTime) + (createDay - 1) * DateTimeUtil.DAY_TIME;
        long newStartTime = hasCreateTime != 0 ? hasCreateTime : startTime;
        boolean needNotify = false;
        if (hasCreateTime == 0) {
            List<ProgramData> affectList = programService.getCurrentAndNextProgram(simpleTask.getEntityId(), 15);
            if (affectList.size() > 0) {
                for (ProgramData programData : affectList) {
                    if (programData.getStartPlayTime().getTime() >= startTime) {
                        logger.info("doAutomationStart sid={} , startTime={} need channelNofify", simpleTask.getId(), startTime);
                        needNotify = true;
                        break;
                    }
                }
            }

            int executeNum = programService.clearAutomation(simpleTask.getEntityId(), startTime);
            if (executeNum < 0) {
                logger.info("[doAutomationStart] executeNum error sid:{}", simpleTask.getId());
                return false;
            }
            executeNum = carouselService.resetAutomation(simpleTask.getEntityId());
            if (executeNum < 0) {
                logger.info("[resetAutomation] executeNum error sid:{}", simpleTask.getId());
                return false;
            }
            if (needNotify) {
                ChannelNotifyUtil.forceNotify(simpleTask.getEntityId());
            }

        }

        newStartTime = programService.findLastEndTime(simpleTask.getEntityId(), newStartTime);
        return doCreateTask(simpleTask, newStartTime, stopCreateTime, params);
    }

    private boolean doAutomationAppend(SimpleTask simpleTask) {
        ChannelBase channelBase = channelService.getChannelBase(simpleTask.getEntityId());
        if (channelBase == null || channelBase.getIsEnable() == -1) {
            logger.info("[doAutomationAppend] channel delete {}", simpleTask.getEntityId());
            doTaskError(simpleTask);
            return false;
        }
        logger.info("[doAutomationAppend] sid={}", simpleTask.getId());
        JSONObject params = JSONObject.parseObject(simpleTask.getParams());
        long checkEndTime = params.getLongValue("checkEndTime");
        long triggerTime = params.getLongValue("triggerTime");
        List<Criterion> cList = new ArrayList<Criterion>();
        cList.add(Restrictions.eq("fatherId", (int) simpleTask.getEntityId()));
        cList.add(Restrictions.gt("qipuId", 0L));
        cList.add(Restrictions.eq("illegalStatus", 0));
        cList.add(Restrictions.eq("deleteFlag", 0));
        List<Order> orderList = new ArrayList<Order>();
        orderList.add(Order.desc("stopPlayTime"));
        List<ProgramData> programDataList = programService.queryDataByCriterion(cList, orderList, 1);
        if (programDataList.size() == 0) {
            logger.info("[doAutomationAppend] programDataList.size zero sid:{}", simpleTask.getId());
            return false;
        }
        long newStartTime = programDataList.get(0).getStopPlayTime().getTime();
        logger.info("[doAutomationAppend] sid:{},pid:{},newStartTime={}, triggerTime:{} ", simpleTask.getId(), programDataList.get(0).getId(), newStartTime, triggerTime);
        if (triggerTime > newStartTime) {
            logger.info("[doAutomationAppend] newStartTime lt  triggerTime . sid:{}", simpleTask.getId());
            newStartTime = triggerTime;
        }
        return doCreateTask(simpleTask, newStartTime, checkEndTime, params);
    }

    private boolean doCreateTask(SimpleTask simpleTask, long newStartTime, long stopCreateTime, JSONObject params) {
        SimpleTaskType type = SimpleTaskType.getTypeByIndex(simpleTask.getTaskType());
        if (type == SimpleTaskType.CAROUSEL_AUTOMATION_START || type == SimpleTaskType.CAROUSEL_AUTOMATION_APPEND) {
            return doCreateProgramEnhance(simpleTask, newStartTime, stopCreateTime, params);
        } else if (type == SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_START || type == SimpleTaskType.CAROUSEL_AUTOMATION_PROGRAM_APPEND) {
            return doCreateAutomationProgram(simpleTask, newStartTime, stopCreateTime, params);
        }
        return false;
    }

    private void doTaskError(SimpleTask simpleTask) {
        logger.info("simpleTask error id:{}", simpleTask.getId());
        simpleTask.setTaskStatus(SimpleTaskStatus.ERROR.getStatusIndex());
        simpleTaskService.saveTask(simpleTask);
    }

    private void doNoDataError(SimpleTask simpleTask) {
        logger.info("simpleTask no_data id:{}", simpleTask.getId());
        simpleTask.setTaskStatus(SimpleTaskStatus.NO_DATA.getStatusIndex());
        simpleTaskService.saveTask(simpleTask);
    }

    private void doSendMailRuleIllegal(AutoCarouselEpisodeRule rule) {
        ChannelBase channelBase = channelService.getChannelBase(rule.getFatherId());
        Map<String, String> map = new HashMap<String, String>();
        map.put(MailConstant.C_NAME, channelBase.getName());
        map.put(MailConstant.C_QIPU_ID, "" + channelBase.getQipuId());
        map.put(MailConstant.SHOW_NAME, rule.getShowName());
        map.put(MailConstant.CAROUSEL_QIPU_ID, "" + rule.getQipuId());
        map.put(MailConstant.ASSIGN_TOS, rule.getOpUser());
        notifyMailService.addMailAsyncTask(0, MailContentUtil.ContentType.AUTOMATION_RULE_ILLEGAL.getTypeIndex(), map);
    }
}
